import { Component, OnInit, Output, Input, EventEmitter, Renderer2, OnDestroy } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';

export type Option = {
  label?: string;
  value: string;
  children?: Option[];
  disabled?: boolean;
  active?: boolean;
};

// export  type Props = {
//   expandTrigger:string;
//   multiple:boolean ;
//   checkStrictly:boolean ;
//   emitPath:boolean ;
//   lazy:boolean ;
//   lazyLoad:any ;
//   value:string ;
//   label:string ;
//   children:string ;
//   disabled:string ;
//   leaf:string ;
// }
export class Props {
  expandTrigger: string = '';
  multiple: boolean = false;
  checkStrictly: boolean = false;
  emitPath: boolean = true;
  lazy: boolean = false;
  lazyLoad: any = function (node: any, resolve: any) { };
  value: string = 'value';
  label: string = 'label';
  children: string = 'children';
  disabled: string = 'disabled';
  //指定选项的叶子节点的标志位为选项对象的某个属性值
  leaf: string = 'leaf';
}
@Component({
  selector: 'el-cascader',
  templateUrl: './cascader.component.html',
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: CascaderComponent,
    multi: true
  }],
})
export class CascaderComponent implements OnInit, OnDestroy, ControlValueAccessor {
  //选中项绑定值
  @Input() model: any = [];
  //选中项绑定值
  @Input() value: any = [];
  //可选项数据源，键名可通过 Props 属性配置
  @Input() options: Option[] = [];
  //配置选项，具体见下表
  @Input() props!: Props;
  //尺寸
  @Input() size: string = '';
  //输入框占位文本
  @Input() placeholder: string = '请选择';
  //是否禁用
  @Input() disabled: boolean = false;
  //是否支持清空选项
  @Input() clearable: boolean = false;
  //输入框中是否显示选中值的完整路径
  @Input('show-all-levels') allLevels: boolean = true;
  //多选模式下是否折叠Tag
  @Input('collapse-tags') collapseTags: boolean = false;
  //选项分隔符
  @Input('separator') separator: string = '';
  //是否可搜索选项
  @Input('filterable') filterable: boolean = false;
  //搜索关键词输入的去抖延迟，毫秒
  @Input('debounce') debounce: number = 300;
  //自定义浮层类名
  @Input('popper-class') popperClass: string = ' ';
  //自定义搜索逻辑，第一个参数是节点node，第二个参数是搜索关键词keyword，通过返回布尔值表示是否命中
  @Input('ilter-method') ilterMethod: any = function (node: any, keyword: any) { };
  //筛选之前的钩子，参数为输入的值，若返回 false 或者返回 Promise 且被 reject，则停止筛选
  @Input('before-filter') beforeFilter: any = function (value: any) { };

  //当选中节点变化时触发
  @Output('change') modelChange: EventEmitter<any> = new EventEmitter();
  //当展开节点发生变化时触发
  @Output('expand-change') expandChange: EventEmitter<any> = new EventEmitter();
  //下拉框出现/隐藏时触发
  @Output('visible-change') visibleChange: EventEmitter<any> = new EventEmitter();
  //在多选模式下，移除Tag时触发
  @Output('remove-tag') removeTag: EventEmitter<any> = new EventEmitter();

  @Input('empty-text') emptyText: string = '没有数据';

  inputHover: boolean = false;
  checkedValue: any = [];


  presentTags: any = [];
  private renderer: any;
  @Input() steps: Array<any> = [];
  @Input() menuVisible: boolean = false;

  @Input() currentLabels: Array<any> = [];
  @Input() globalListenFunc: any;
  @Input('change-on-select') changeOnSelect: boolean = false;
  @Input() checkStrictly: boolean = false;
  private controlChange: any = function () { };
  private controlTouch: any = function () { };

  constructor(renderer: Renderer2) {
    this.renderer = renderer;
  };


  readonly(): boolean {
    return this.filterable && this.props && this.props.multiple;
  }

  multiple(): boolean {
    if (!this.props) {
      return false;
    }
    return this.props.multiple ? true : false;
  }

  showClearIcon(): boolean {
    return !!(this.clearable && this.inputHover && this.currentLabels.length);
  }

  deleteTag(index: number) {
    console.log(index)
  }

  handleSuggestionClick(index: number) {
    console.log(index)
  }

  handleExpandChange() {

  }

  toggleDropDownVisible(isEven: boolean) {

  }

  close(): void {
    this.menuVisible = false;
    this.globalListenFunc && this.globalListenFunc();
  };
  clickHandle(event: MouseEvent): void {
    event.stopPropagation()
    if (this.disabled) return

    const element: HTMLElement = event.target as HTMLElement
    const isSelfTrigger = ['SPAN', 'I', 'INPUT'].find(v => v === element.tagName)
    
    if (!isSelfTrigger) return
    this.menuVisible = !this.menuVisible

    if (this.menuVisible) {
      this.globalListenFunc = this.renderer.listen(
        'document', 'click', () => {
          this.menuVisible = false
        }
      )
    } else {
      this.globalListenFunc && this.globalListenFunc()
    }
  }

  changeLabels(): void {
    const nextValue: Option[] = []
    this.steps.forEach((items: Option[]) => {
      const steps: Option[] = items.filter((item: Option) => item.active)
      nextValue.push(steps[0])
    })
    this.currentLabels = nextValue
    const next = nextValue.map((item: Option) => item.value)
    this.model = next
    this.modelChange.emit(next)
    this.controlChange(next)
  }

  clearValue(event?: Event): void {
    event && event.stopPropagation()
    this.currentLabels = []
    const step1 = this.options.map((option: Option) =>
      Object.assign(option, {
        active: false,
      }))
    this.steps = [step1]
    this.menuVisible = false
  }

  selectHandle(event: Event, step: number, index: number): any {
    event.stopPropagation()
console.log(event, step, index,this.steps);
    if (this.steps[step][index].elDisabled) return
    this.steps[step] = this.steps[step].map((item: Option, i: number) =>
      Object.assign(item, { active: i === index }))
    // reset steps
    this.steps.length = step + 1
    const next = this.steps[step][index].children

    // go next
    if (next && Array.isArray(next)) {
      // change on select (props)
      this.changeOnSelect && this.changeLabels()
      const nativeNext = next.map((item: Option) => Object.assign(item, { active: false }))
      return this.steps.push(nativeNext)
    }
    // last step
    this.changeLabels()
    this.menuVisible = false
  }



  ngOnInit(): void {
    this.clearValue()
    if (this.model && this.model.length) {
      const getLabel = (options: Option[], val: string) => {
        const item: Option = options.filter((item: Option) => item.value === val)[0]
        return { children: item.children, val: item }
      }

      let options: any = this.options
      const val: Option[] = this.model.map((v: string) => {
        const { children, val } = getLabel(options, v)
        options = children
        return val
      })
      this.currentLabels = val.filter(v => !!v)

    }
  }

  ngOnDestroy(): void {
    this.globalListenFunc && this.globalListenFunc()
  }

  writeValue(value: any): void {
    this.model = value
  }

  registerOnChange(fn: Function): void {
    this.controlChange = fn
  }

  registerOnTouched(fn: Function): void {
    this.controlTouch = fn
  }
}
